/***************************************************************************************
* Copyright (c) 2014-2021 Zihao Yu, Nanjing University
* Copyright (c) 2020-2022 Institute of Computing Technology, Chinese Academy of Sciences
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

static inline def_DHelper(csr) {
  decode_op_r(s, id_src1, s->isa.instr.i.rs1, true);
  decode_op_i(s, id_src2, s->isa.instr.csr.csr, true);
  decode_op_r(s, id_dest, s->isa.instr.i.rd, false);

  // TODO: use csr name
  print_Dop(id_src2->str, OP_STR_SIZE, "csr_0x%x", s->isa.instr.csr.csr);
}

static inline def_DHelper(csri) {
  decode_op_i(s, id_src1, s->isa.instr.i.rs1, true);
  decode_op_i(s, id_src2, s->isa.instr.csr.csr, true);
  decode_op_r(s, id_dest, s->isa.instr.i.rd, false);

  // TODO: use csr name
  print_Dop(id_src2->str, OP_STR_SIZE, "csr_0x%x", s->isa.instr.csr.csr);
}

static inline def_DHelper(hlv) {
  // Similar to DHelper I / SubDHelper load
  decode_op_r(s, id_src1, s->isa.instr.i.rs1, true);  // addr reg
  decode_op_r(s, id_dest, s->isa.instr.i.rd, false);  // dest reg
  print_Dop(id_src1->str, OP_STR_SIZE, "(%s)", reg_name(s->isa.instr.i.rs1, 4));
}

static inline def_DHelper(hsv) {
  // Similar to DHelper S / SubDHelper store
  decode_op_r(s, id_src1, s->isa.instr.s.rs1, true);  // addr reg
  decode_op_r(s, id_dest, s->isa.instr.s.rs2, true);  // src reg
  // Note: Put rs2 to id_dest, for print_asm_template2
  print_Dop(id_src1->str, OP_STR_SIZE, "(%s)", reg_name(s->isa.instr.s.rs1, 4));
}

// funct3 == 000
def_THelper(priv) {
  def_INSTR_TAB  ("0000000 00000 00000 ??? 00000 ????? ??",      ecall);
  def_INSTR_TAB  ("0000000 00001 00000 ??? 00000 ????? ??",      ebreak);

  def_INSTR_TAB  ("0001000 00010 00000 ??? 00000 ????? ??",      sret);
  def_INSTR_TAB  ("0011000 00010 00000 ??? 00000 ????? ??",      mret);
#ifdef CONFIG_RV_SMRNMI
  def_INSTR_TAB  ("0111000 00010 00000 ??? 00000 ????? ??",      mnret);
#endif // CONFIG_RV_SMRNMI  

  def_INSTR_TAB  ("0001000 00101 00000 ??? 00000 ????? ??",      wfi);

#ifdef CONFIG_RV_ZAWRS
  def_INSTR_TAB  ("0000000 01101 00000 ??? 00000 ????? ??",      wrs_nto);
  def_INSTR_TAB  ("0000000 11101 00000 ??? 00000 ????? ??",      wrs_sto);
#endif //CONFIG_RV_ZAWRS

  def_INSTR_IDTAB("0001001 ????? ????? ??? 00000 ????? ??", R  , sfence_vma);
#ifdef CONFIG_RVH
  def_INSTR_IDTAB("0010001 ????? ????? ??? 00000 ????? ??", R  , hfence_vvma);
  def_INSTR_IDTAB("0110001 ????? ????? ??? 00000 ????? ??", R  , hfence_gvma);
#endif // CONFIG_RVH

#ifdef CONFIG_RV_SVINVAL
  def_INSTR_TAB  ("0001100 00000 00000 ??? 00000 ????? ??",      sfence_w_inval);
  def_INSTR_TAB  ("0001100 00001 00000 ??? 00000 ????? ??",      sfence_inval_ir);
  def_INSTR_IDTAB("0001011 ????? ????? ??? 00000 ????? ??", R  , sinval_vma);
  #ifdef CONFIG_RVH
  def_INSTR_IDTAB("0010011 ????? ????? ??? 00000 ????? ??", R  , hinval_vvma);
  def_INSTR_IDTAB("0110011 ????? ????? ??? 00000 ????? ??", R  , hinval_gvma);
  #endif // CONFIG_RVH
#endif // CONFIG_RV_SVINVAL

  return EXEC_ID_inv;
}

// funct3 == 100
def_THelper(privm) {
#ifdef CONFIG_RV_ZIMOP
  def_INSTR_IDTAB("1?00??0 111?? ????? ??? ????? ????? ??", I,   mop_r_n);
  def_INSTR_IDTAB("1?00??1 ????? ????? ??? ????? ????? ??", R,   mop_rr_n);
#endif // CONFIG_RV_ZIMOP

#ifdef CONFIG_RVH
  def_INSTR_IDTAB("0110000 00000 ????? ??? ????? ????? ??", hlv, hlv_b);
  def_INSTR_IDTAB("0110000 00001 ????? ??? ????? ????? ??", hlv, hlv_bu);
  def_INSTR_IDTAB("0110010 00000 ????? ??? ????? ????? ??", hlv, hlv_h);
  def_INSTR_IDTAB("0110010 00001 ????? ??? ????? ????? ??", hlv, hlv_hu);
  def_INSTR_IDTAB("0110100 00000 ????? ??? ????? ????? ??", hlv, hlv_w);
  def_INSTR_IDTAB("0110100 00001 ????? ??? ????? ????? ??", hlv, hlv_wu);
  def_INSTR_IDTAB("0110110 00000 ????? ??? ????? ????? ??", hlv, hlv_d);

  def_INSTR_IDTAB("0110010 00011 ????? ??? ????? ????? ??", hlv, hlvx_hu);
  def_INSTR_IDTAB("0110100 00011 ????? ??? ????? ????? ??", hlv, hlvx_wu);

  def_INSTR_IDTAB("0110001 ????? ????? ??? 00000 ????? ??", hsv, hsv_b);
  def_INSTR_IDTAB("0110011 ????? ????? ??? 00000 ????? ??", hsv, hsv_h);
  def_INSTR_IDTAB("0110101 ????? ????? ??? 00000 ????? ??", hsv, hsv_w);
  def_INSTR_IDTAB("0110111 ????? ????? ??? 00000 ????? ??", hsv, hsv_d);
#endif // CONFIG_RVH

  return EXEC_ID_inv;
}

// All System instructions decode start from here
def_THelper(system) {
  def_INSTR_TAB  ("??????? ????? ????? 000 ????? ????? ??",      priv);
  def_INSTR_TAB  ("??????? ????? ????? 100 ????? ????? ??",      privm);

  def_INSTR_IDTAB("??????? ????? ????? 001 ????? ????? ??", csr, csrrw);
  def_INSTR_IDTAB("??????? ????? ????? 010 ????? ????? ??", csr, csrrs);
  def_INSTR_IDTAB("??????? ????? ????? 011 ????? ????? ??", csr, csrrc);

  def_INSTR_IDTAB("??????? ????? ????? 101 ????? ????? ??", csri, csrrwi);
  def_INSTR_IDTAB("??????? ????? ????? 110 ????? ????? ??", csri, csrrsi);
  def_INSTR_IDTAB("??????? ????? ????? 111 ????? ????? ??", csri, csrrci);

  return EXEC_ID_inv;
}
